package com.start.form.engine.core.storage;

import com.alibaba.fastjson2.JSONObject;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.start.common.dataRule.StartQueryWrapper;
import com.start.common.entity.StartBaseMenu;
import com.start.common.exceptions.StartBusException;
import com.start.common.service.GlobalBaseMenuService;
import com.start.common.tools.SpringContextTools;
import com.start.form.engine.core.StartColumnInfo;
import com.start.form.engine.core.StartDataAction;
import com.start.form.engine.core.TableDataEngineService;
import com.start.form.engine.core.TableEngineService;
import com.start.form.engine.core.entity.StartFormConfig;
import com.start.form.engine.core.global.StartGlobalTableDataListener;
import com.start.form.engine.core.global.StartGlobalTableListener;
import com.start.form.engine.core.model.StartFormColumnModel;
import com.start.form.engine.core.model.StartFormConfigModel;
import com.start.form.engine.core.rule.DataRuleVerification;
import com.start.form.engine.core.service.StartFormConfigService;
import com.start.form.engine.core.tools.StartAvueColTools;
import org.apache.commons.lang3.StringUtils;
import org.springframework.transaction.annotation.Transactional;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

public abstract class StartBaseFormStorageEngineService implements TableDataEngineService, TableEngineService {

    private final StartFormConfigService startFormConfigService;
    private final GlobalBaseMenuService globalBaseMenuService;

    public StartBaseFormStorageEngineService() {
        startFormConfigService = SpringContextTools.getBean(StartFormConfigService.class);
        globalBaseMenuService = SpringContextTools.getBean(GlobalBaseMenuService.class);
    }

    /**
     * 查看列
     *
     * @param tableId
     * @return
     */
    @Override
    public List<StartFormColumnModel> getColumnConfig(String tableId) {
        StartFormConfigModel table = getTable(tableId);
        return getColumnConfig(table);
    }

    /**
     * 获取表配置
     *
     * @param tableId    表id
     * @param loadColumn 是否加载列信息
     * @return
     */
    @Override
    public StartFormConfigModel getTable(String tableId, boolean loadColumn) {
        StartFormConfig config = startFormConfigService.getById(tableId);
        if (config == null) return null;
        return getTable(config, loadColumn);
    }

    /**
     * 获取表信息
     *
     * @param config      表配置
     * @param loadColumns 是否加载列信息
     * @return
     */
    @Override
    public final StartFormConfigModel getTable(StartFormConfig config, boolean loadColumns) {
        StartFormConfigModel model = null;
        if (!(config instanceof StartFormConfigModel)) {
            model = ((JSONObject) JSONObject.from(config)).toJavaObject(StartFormConfigModel.class);
        } else {
            model = (StartFormConfigModel) config;
        }
        if (!loadColumns) return model;
        if (model.getColumns() != null && !model.getColumns().isEmpty()) return model;
        List<StartFormColumnModel> column = getStoreColumn(model);
        model.setColumns(column);
        return model;
    }


    /**
     * 创建表
     *
     * @param config 数据表配置
     */
    @Override
    @Transactional
    public void createTable(StartFormConfig config) {
        StartGlobalTableListener.getInstance().beforeCreateTable(config);
        if (StringUtils.isAllBlank(config.getFormCode())) {
            config.setFormCode(config.getTableName());
        }
        startFormConfigService.save(config);
        StartGlobalTableListener.getInstance().afterCreateTable(config);
    }


    /**
     * 修改表
     *
     * @param config 数据表配置
     */
    @Override
    @Transactional
    public void updateTable(StartFormConfig config) {
        List<StartFormColumnModel> tableColumnsOld = getStoreColumn(config);
        StartGlobalTableListener.getInstance().beforeUpdateTable(config, tableColumnsOld);
        startFormConfigService.updateById(config);
        StartGlobalTableListener.getInstance().afterUpdateTable(config);
    }

    /**
     * 获取数据表列信息
     *
     * @param config 数据表信息
     * @return
     */
    @Override
    public List<StartFormColumnModel> getStoreColumn(StartFormConfig config) {
        return getColumnConfig(config);
    }

    /**
     * 删除数据表
     *
     * @param formConfig 数据表配置
     */
    @Override
    @Transactional
    public void deleteTable(StartFormConfig formConfig) {
        StartGlobalTableListener.getInstance().beforeDeleteTable(formConfig);
        storageDeleteTable(formConfig);
        startFormConfigService.removeById(formConfig.getId());
        StartGlobalTableListener.getInstance().afterDeleteTable(formConfig);
    }

    protected abstract void storageDeleteTable(StartFormConfig formConfig);

    /**
     * 同步数据表
     *
     * @param formConfig 表单培训形象
     */
    @Override
    public final void synchronizationTable(StartFormConfig formConfig) {
        JSONObject object = formConfig.getFormOption();
        List<StartFormColumnModel> oldColumns = getStoreColumn(formConfig);
        StartColumnInfo startColumnInfo;
        if ("dynamic".equals(object.getString("type"))) {
            object = object.getJSONObject("children");
        }
        startColumnInfo = new StartColumnInfo(object.getJSONArray("column"), oldColumns, true);
        StartGlobalTableListener.getInstance().beforeSynchronizationTable(formConfig, startColumnInfo);
        StartAvueDynamicStore.getInstance().syncDynamicTable(formConfig);
        List<StartFormColumnModel> startFormColumns = storageSynchronizationTable(formConfig, startColumnInfo);
        StartAvueColTools.updateTableOption(startFormColumns, object);
        long count = startFormConfigService.getTableHistoryCount(formConfig.getTableName());
        formConfig.setTableVersion(count + 1);
        formConfig.setLastVersion(count);
        formConfig.setIsSyncDataBase(false);
        formConfig.setFormOption(object);
        if (StringUtils.isAllBlank(formConfig.getId())) {
            startFormConfigService.save(formConfig);
        } else {
            startFormConfigService.updateById(formConfig);
            formConfig.setId(null);
            formConfig.setTableVersion(0L);
            startFormConfigService.save(formConfig);
        }
        StartGlobalTableListener.getInstance().afterSynchronizationTable(formConfig, startFormColumns, startColumnInfo);
    }


    protected abstract List<StartFormColumnModel> storageSynchronizationTable(StartFormConfig formConfig, StartColumnInfo startColumnInfo);


    /**
     * 创建菜单
     *
     * @param tableId      数据表id
     * @param menuLabel    菜单名称
     * @param menuParentId 父级菜单
     */
    public final void createMenu(String tableId, String menuLabel, String menuParentId) {
        if (StringUtils.isEmpty(tableId)) throw new StartBusException("表单Id不能空！");
        if (globalBaseMenuService == null) {
            throw new StartBusException("未能找到一个bean 实现类了：" + GlobalBaseMenuService.class + " 中的方法");
        }
        StartBaseMenu parentSysMenu = new StartBaseMenu();
        if (!StringUtils.isEmpty(menuParentId)) parentSysMenu = globalBaseMenuService.getGlobalMenuById(menuParentId);
        if (parentSysMenu == null) throw new StartBusException("父级菜单不存在！");
        StartFormConfigModel dynamicTable = getTable(tableId);
        if (dynamicTable == null) throw new StartBusException("表单信息不存在！");
        StartBaseMenu menuView = new StartBaseMenu();
        menuView.setLabel(menuLabel);
        menuView.setParentId(menuParentId);
        menuView.setDynamicFormId(tableId);
        menuView.setPath("/" + dynamicTable.getId());
        menuView.setComponent("views/form-engine/data/BusMenuIndex");
        globalBaseMenuService.saveGlobalMenu(menuView);
        List<StartBaseMenu> menuBtns = new ArrayList<>();
        menuBtns.add(StartBaseMenu.createBtn(dynamicTable.getId() + ":add", "新增", menuView.getId()));
        menuBtns.add(StartBaseMenu.createBtn(dynamicTable.getId() + ":edit", "修改", menuView.getId()));
        menuBtns.add(StartBaseMenu.createBtn(dynamicTable.getId() + ":remove", "删除", menuView.getId()));
        menuBtns.add(StartBaseMenu.createBtn(dynamicTable.getId() + ":exportExcel", "导入", menuView.getId()));
        menuBtns.add(StartBaseMenu.createBtn(dynamicTable.getId() + ":importExcel", "导出", menuView.getId()));
        globalBaseMenuService.saveBatchGlobalMenu(menuBtns);
        dynamicTable.setIsCreateMenu(true);
        startFormConfigService.updateById(dynamicTable);
    }

    /**
     * 分页查询
     *
     * @param page   分页信息
     * @param config 配置信息
     * @param query  查询条件
     * @return Page<JSONObject> 对象
     */
    @Override
    public final Page<?> page(StartFormConfig config, Page page, StartQueryWrapper query) {
        List<StartFormColumnModel> column = getStoreColumn(config);
        StartGlobalTableDataListener.getInstance().beforeQueryData(config, query);
        Page resultPage = storagePage(config, page, column, query);
        List records = resultPage.getRecords();
        JSONObject[] dataList = new JSONObject[records.size()];
        for (int i = 0; i < records.size(); i++) {
            dataList[i] = JSONObject.from(records.get(i));
        }
        records.clear();
        StartGlobalTableDataListener.getInstance().afterQueryData(config, query, dataList);
        resultPage.setRecords(Arrays.asList(dataList));
        return resultPage;
    }

    protected abstract Page storagePage(StartFormConfig config, Page page, List<StartFormColumnModel> column, StartQueryWrapper query);


    @Override
    public List<JSONObject> list(StartFormConfig config, StartQueryWrapper query) {
        List<StartFormColumnModel> column = getStoreColumn(config);
        StartGlobalTableDataListener.getInstance().beforeQueryData(config, query);
        List<JSONObject> list = storageList(config, column, query);
        JSONObject[] dataList = new JSONObject[list.size()];
        for (int i = 0; i < list.size(); i++) {
            JSONObject item = JSONObject.from(list.get(i));
            StartAvueDynamicStore.getInstance().handlerDynamicSelect(config, item);
            dataList[i] = item;
        }
        list.clear();
        StartGlobalTableDataListener.getInstance().afterQueryData(config, query, dataList);
        return Arrays.asList(dataList);
    }

    protected abstract List<JSONObject> storageList(StartFormConfig config, List<StartFormColumnModel> column, StartQueryWrapper query);

    /**
     * 保存数据
     *
     * @param config 配置
     * @param data   待保存的数据
     * @return
     */

    @Override
    public final String save(StartFormConfig config, JSONObject data) {
        List<StartFormColumnModel> columns = getColumnConfig(config);
        for (StartFormColumnModel column : columns) {
            DataRuleVerification.verification(column, data.getString(column.getProp()), StartDataAction.ADD);
        }
        StartGlobalTableDataListener.getInstance().beforeSaveData(config, data);
        String dataId = storageSave(config, columns, data);
        StartAvueDynamicStore.getInstance().save(config, dataId, data);
        StartGlobalTableDataListener.getInstance().afterSaveData(config, data);
        return dataId;
    }

    protected abstract String storageSave(StartFormConfig config, List<StartFormColumnModel> columns, JSONObject data);

    /**
     * 修改数据
     *
     * @param config       数据表配置
     * @param data         新数据
     * @param queryWrapper 修改条件
     * @return
     */
    @Override
    public final long update(StartFormConfig config, JSONObject data, StartQueryWrapper queryWrapper) {
        StartGlobalTableDataListener.getInstance().beforeUpdate(config, data, queryWrapper);
        List<StartFormColumnModel> column = getStoreColumn(config);
        List<JSONObject> jsonObjects = storageList(config, column, queryWrapper);
        long num = storageUpdate(config, column, data, queryWrapper);
        for (JSONObject jsonObject : jsonObjects) {
            String mainDataId = jsonObject.getString(COLUMN_PK_NAME);
            StartAvueDynamicStore.getInstance().update(config, mainDataId, data);
        }
        StartGlobalTableDataListener.getInstance().afterUpdate(config, data, queryWrapper);
        return num;
    }

    protected abstract long storageUpdate(StartFormConfig config, List<StartFormColumnModel> columns, JSONObject data, StartQueryWrapper queryWrapper);

    /**
     * 删除数据
     *
     * @param config       数据表配置
     * @param queryWrapper 删除条件
     * @return
     */
    @Override
    public final long remove(StartFormConfig config, StartQueryWrapper queryWrapper) {
        StartGlobalTableDataListener.getInstance().beforeDelete(config, queryWrapper);
        List<StartFormColumnModel> column = getStoreColumn(config);
        List<JSONObject> jsonObjects = storageList(config, column, queryWrapper);
        long count = storageRemove(config, queryWrapper);
        for (JSONObject jsonObject : jsonObjects) {
            String mainDataId = jsonObject.getString(COLUMN_PK_NAME);
            StartAvueDynamicStore.getInstance().remove(config, mainDataId);
        }
        StartGlobalTableDataListener.getInstance().afterDelete(config, queryWrapper);
        return count;
    }

    /**
     * 删除数据
     *
     * @param config       数据表配置
     * @param queryWrapper 条件
     * @return
     */
    protected abstract long storageRemove(StartFormConfig config, StartQueryWrapper queryWrapper);

    /**
     * 查询数据数量
     *
     * @param config       数据表配置
     * @param queryWrapper 条件
     * @return
     */
    @Override
    public final long count(StartFormConfig config, StartQueryWrapper queryWrapper) {
        StartGlobalTableDataListener.getInstance().beforeCount(config, queryWrapper);
        long count = storageCount(config, queryWrapper);
        StartGlobalTableDataListener.getInstance().afterCount(config, queryWrapper);
        return count;
    }

    /**
     * 查询数据数量
     *
     * @param config       数据表配置
     * @param queryWrapper 查询条件
     * @return
     */
    protected abstract long storageCount(StartFormConfig config, StartQueryWrapper queryWrapper);
}
